home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1998 June / SGI Freeware 1998 June.iso / dist / fw_ATxgopher.idb / usr / freeware / src / xgopher.1.3 / text.c.z / text.c
C/C++ Source or Header  |  1998-01-21  |  19KB  |  852 lines

  1. /* text.c
  2.    make and manage the text popups */
  3.  
  4.      /*---------------------------------------------------------------*/
  5.      /* Xgopher        version 1.3     08 April 1993                  */
  6.      /*                version 1.2     20 November 1992               */
  7.      /*                version 1.1     20 April 1992                  */
  8.      /*                version 1.0     04 March 1992                  */
  9.      /* X window system client for the University of Minnesota        */
  10.      /*                                Internet Gopher System.        */
  11.      /* Allan Tuchman, University of Illinois at Urbana-Champaign     */
  12.      /*                Computing and Communications Services Office   */
  13.      /* Copyright 1992, 1993 by                                       */
  14.      /*           the Board of Trustees of the University of Illinois */
  15.      /* Permission is granted to freely copy and redistribute this    */
  16.      /* software with the copyright notice intact.                    */
  17.      /*---------------------------------------------------------------*/
  18.  
  19.  
  20. #include <stdio.h>
  21.  
  22. /* #include <sys/file.h> */ /* now comes from osdep.h */
  23.  
  24. #include <X11/Intrinsic.h>
  25. #include <X11/StringDefs.h>
  26.  
  27. #include <X11/Xaw/Box.h>
  28. #include <X11/Xaw/Command.h>
  29. #include <X11/Xaw/Form.h>
  30. #include <X11/Xaw/Label.h>
  31. #include <X11/Xaw/AsciiText.h>
  32. #include <X11/Xaw/Viewport.h>
  33. #include <X11/Shell.h>
  34.  
  35. #include "compatR4.h"
  36.  
  37. #if XtSpecificationRelease > 5
  38. #define XGOPHER_X11R6        /* KeySink widget won't compile under R6 yet */
  39. #else
  40. #include "KeyWSink.h"        /* KeySink works fine for R4 & R5 */
  41. #endif
  42.  
  43. #include "conf.h"
  44. #include "osdep.h"
  45. #include "appres.h"
  46. #include "xglobals.h"
  47. #include "text.h"
  48. #include "misc.h"
  49. #include "subst.h"
  50. #include "gopher.h"
  51. #include "item.h"
  52.  
  53. #define    PERCENT    '%'
  54.  
  55. typedef struct _subItem {
  56.         char    title[USER_STRING_LEN];
  57.         char    host[HOST_STRING_LEN];
  58.     } subItem;
  59.  
  60. typedef struct _textElement {
  61.         Widget        textShell;
  62.         Widget        textDisplay;
  63.         int        seqNumber;
  64.         TextClass    class;
  65.         subItem        origFields;
  66.         Boolean        used;
  67.         Boolean        hold;
  68.         Boolean        deleteFile;
  69.         char        *displayedFile;
  70.         char        **wordList;
  71.         char        *stringValue;
  72.         struct _textElement *next;
  73.     } textElement, *textElementP;
  74.  
  75. static    textElementP    textElementHead = NULL;
  76.  
  77. static    textSeqNumber = 0;
  78.  
  79. #define THIS_POPUP_NAME        "textPopup"
  80.  
  81.                 /* default values */
  82. static popupPosResources    placement = {
  83.  
  84.     /* position at the top of the main panel, centered across */
  85.     from_none, 0, 0, justify_top_left, justify_top_left, False, False
  86.     };
  87.  
  88.  
  89.  
  90. /* textStringToFile
  91.    if a text widget has a string, rather than file value, copy the
  92.    string to a file, and set the structure to reflect this so things
  93.    will be cleaned up. */
  94.  
  95. static Boolean
  96. textStringToFile(tep)
  97. textElementP    tep;
  98. {
  99.     char    *tempfile = XtMalloc(sizeof(char) * PATH_NAME_LEN);
  100.     FILE    *fp;
  101.  
  102.     getTempFile(tempfile);
  103.     if ((fp = fopen (tempfile, "w")) == NULL) {
  104.         return False;
  105.     }
  106.     fwrite (tep->stringValue, sizeof(char),
  107.                 strlen(tep->stringValue), fp);
  108.     fclose(fp);
  109.     tep->displayedFile = tempfile;
  110.     tep->deleteFile = True;
  111.     free(tep->stringValue);        /* free(), not XtFree() */
  112.     tep->stringValue = NULL;
  113.  
  114.     return True;
  115. }
  116.  
  117.  
  118. /* pageDownProc
  119.    scroll down a page in a text widget */
  120.  
  121. void
  122. pageDownProc(w, client_data, call_data)
  123. Widget        w;
  124. XtPointer    client_data, call_data;
  125. {
  126.     Widget    tw = (Widget) client_data;
  127.  
  128.     XtCallActionProc(tw, "next-page", NULL, NULL, 0);
  129. }
  130.  
  131.  
  132. /* pageUpProc
  133.    scroll up a page in a text widget */
  134.  
  135. void
  136. pageUpProc(w, client_data, call_data)
  137. Widget        w;
  138. XtPointer    client_data, call_data;
  139. {
  140.     Widget    tw = (Widget) client_data;
  141.  
  142.     XtCallActionProc(tw, "previous-page", NULL, NULL, 0);
  143. }
  144.  
  145.  
  146. /* holdProc
  147.    hold the text window up, possibly overriding the concurrentText resource. */
  148.  
  149. void
  150. holdProc(w, client_data, call_data)
  151. Widget        w;
  152. XtPointer    client_data, call_data;
  153. {
  154.     textElementP    tep = (textElementP) client_data;
  155.  
  156.     tep->hold = True;
  157. }
  158.  
  159.  
  160. /* printProc
  161.    send the contents of a text widget to the printer */
  162.  
  163. void
  164. printProc(w, client_data, call_data)
  165. Widget        w;
  166. XtPointer    client_data, call_data;
  167. {
  168.     textElementP    tep = (textElementP) client_data;
  169.     char        *fileName;
  170.     char        *printCommand;
  171.     char        errorMessage[MESSAGE_STRING_LEN];
  172.     char        *out, *in, *f;
  173.     Boolean        hasFile = False;
  174.     gopherItemP    fakeGI;
  175.  
  176.     if (! appResources->allowPrint) {
  177.         return;
  178.     }
  179.  
  180.     if (tep->displayedFile == NULL) {
  181.         if (! textStringToFile(tep) ) {
  182.             showError(
  183. "Text cannot be printed because a temporary file cannot be created.");
  184.             return;
  185.         }
  186.     }
  187.  
  188.     fakeGI = newItem();
  189.     strcpy(fakeGI->host, tep->origFields.host);
  190.     strcpy(USER_STRING(fakeGI), tep->origFields.title);
  191.     fakeGI->port = 0;
  192.  
  193.     fileName = tep->displayedFile;
  194.  
  195.     printCommand = editCommand(fakeGI, appResources->printCommand,
  196.                 fileName, fileName);
  197.     
  198.  
  199.     if (system(printCommand) == 127) {
  200.         sprintf (errorMessage,
  201.             "The print command could not be executed:\n%s",
  202.             printCommand);
  203.         showError(errorMessage);
  204.     }
  205.     freeItem(fakeGI);
  206.     free(printCommand);
  207.  
  208.     return;
  209. }
  210.  
  211.  
  212. /* saveDisplayedText
  213.    copy a displayed text file to a user-specified file obtained from the
  214.    file-save popup.  This routine is a callback to that popup. */
  215.  
  216. BOOLEAN
  217. saveDisplayedText(outFD, clientData)
  218. int        outFD;
  219. XtPointer    clientData;
  220. {
  221.     textElementP    tep = (textElementP) clientData;
  222.     int    inFD;
  223.  
  224.     if (tep->displayedFile == NULL) {
  225.         write( outFD, tep->stringValue,
  226.                 sizeof(char)*strlen(tep->stringValue) );
  227.     } else {
  228.         if ((inFD = open(tep->displayedFile, O_RDONLY, 0)) < 0) {
  229.             showError( "Problem saving text file" );
  230.             return FALSE;
  231.         }
  232.  
  233.         {
  234. #define            BUF_SZ    1024
  235.             char    buf[BUF_SZ];
  236.             int        cc;
  237.  
  238.             cc = read(inFD, buf, BUF_SZ);
  239.             while (cc > 0) {
  240.             (void) write(outFD, buf, cc);
  241.             cc = read(inFD, buf, BUF_SZ);
  242.             }
  243.  
  244.             if (cc < 0) {
  245.             close(inFD);
  246.             return FALSE;
  247.             }
  248.         }
  249.     }
  250.     
  251.     close (inFD);
  252.     return TRUE;
  253. }
  254.  
  255.  
  256. /* saveProc
  257.    save the contents of a text widget to a file */
  258.  
  259. void
  260. saveProc(w, client_data, call_data)
  261. Widget        w;
  262. XtPointer    client_data, call_data;
  263. {
  264.     textElementP    tep = (textElementP) client_data;
  265.  
  266.     if (tep == NULL) return;
  267.  
  268.     if (! appResources->allowSave) {
  269.         return;
  270.     }
  271.  
  272.     saveRequest( tep->textShell, (XtPointer) tep);
  273. }
  274.  
  275.  
  276. /* freeTextResources
  277.    free all resources associated with a textElement structure. */
  278.  
  279. static void
  280. freeTextResources(tep)
  281. textElementP    tep;
  282. {
  283.     if (tep->deleteFile)
  284.         if (unlink(tep->displayedFile) != 0) {
  285.             fprintf (stderr,
  286.         "Warning: a gopher internal file could not be removed.\n");
  287.             fprintf (stderr,
  288.                 "         This may indicate a system error.\n");
  289.         }
  290.  
  291.     if (tep->displayedFile != NULL) {
  292.         XtFree(tep->displayedFile);
  293.         tep->displayedFile = NULL;
  294.     }
  295.     freeWordList(tep->wordList);
  296.     tep->wordList      = NULL;
  297.     tep->deleteFile    = False;
  298.     if (tep->stringValue != NULL) {
  299.         free(tep->stringValue);        /* free(), not XtFree() */
  300.     }
  301.     tep->stringValue   = NULL;
  302.  
  303. #ifdef XGOPHER_X11R4
  304.     /* the following should not be necessary, but some R4 versions
  305.        seem to not really free their string value! */
  306.  
  307.     {
  308.         Cardinal        n;
  309.         Arg             args[3];
  310.  
  311.         n = 0;
  312.         XtSetArg(args[n], XtNtype, XawAsciiString);  n++;
  313.         XtSetArg(args[n], XtNstring, "");  n++;
  314.         XtSetValues(tep->textDisplay, args, n);
  315.     }
  316. #endif  /* XGOPHER_X11R4 */
  317. }
  318.  
  319.  
  320. /* doneProc
  321.    Done showing text file in a popup, clean up */
  322.  
  323. void
  324. doneProc(w, client_data, call_data)
  325. Widget        w;
  326. XtPointer    client_data, call_data;
  327. {
  328.     int        i;
  329.     textElementP    tep = (textElementP) client_data;
  330.  
  331.     if (tep == NULL) return;
  332.  
  333.     XtPopdown(tep->textShell);
  334.  
  335.     freeTextResources(tep);
  336.     tep->used = False;
  337.  
  338.     return;
  339. }
  340.  
  341.  
  342. /* cleanUpTextProc
  343.    Allow a final chance to remove all the temp files text knows about. */
  344.  
  345. void
  346. cleanUpTextProc()
  347. {
  348.     textElementP    tep;
  349.  
  350.  
  351.     for (tep=textElementHead; tep != NULL; tep = tep->next) 
  352.         if (tep->used && tep->deleteFile)
  353.             (void) unlink(tep->displayedFile);
  354.     
  355.     return;
  356. }
  357.  
  358.  
  359. /* RemoveText
  360.    handle a done action specified via a translation.
  361.    Capitalization is for X convention. */
  362.  
  363. static void
  364. RemoveText(w, event, params, numParams)
  365. Widget          w;
  366. XEvent          *event;
  367. String          *params;
  368. Cardinal        *numParams;
  369. {
  370.     Widget        button;
  371.     textElementP    tep;
  372.  
  373.     /* need the widget id of the Done button for that particular
  374.        text window. */
  375.     
  376.     button = XtNameToWidget(w, "*textDone");
  377.  
  378.         XtCallCallbacks(button, XtNcallback, NULL);
  379. }
  380.  
  381.  
  382. /* removeAllText
  383.    invoke the "done" callback for each text window displayed */
  384.  
  385. void
  386. removeAllText()
  387. {
  388.     textElementP    tep;
  389.  
  390.     for (tep=textElementHead; tep != NULL; tep = tep->next) 
  391.         if (tep->used)
  392.             doneProc(tep->textShell, tep, NULL);
  393.     
  394.     return;
  395. }
  396.  
  397.  
  398. /* createTextShell
  399.    Build a text popup */
  400.  
  401. static textElementP
  402. createTextShell(topLevel)
  403. Widget    topLevel;
  404. {
  405.     Widget        doneButton, pageDownButton, pageUpButton, 
  406.             printButton, saveButton, holdButton;
  407.     Widget        buttonBox, textForm;
  408.     Arg        args[10];
  409.     Cardinal    n;
  410.     int        i, w, h;
  411.     textElementP    tep;
  412.     Widget        kwSink;
  413.  
  414.     static Boolean    actionsAdded=False;
  415.     static XtActionsRec     actionsTable[] = {
  416.                 {"removeText",   RemoveText}
  417.                 };
  418.  
  419.     if (!actionsAdded) {
  420.         XtAppAddActions(appcon, actionsTable, XtNumber(actionsTable));
  421.         actionsAdded = True;
  422.  
  423.         /* find the popup placement for this shell */
  424.  
  425.         {
  426.         popupPosResources *resourcePlacement;
  427.  
  428.         resourcePlacement = getPopupPosResources(
  429.                     THIS_POPUP_NAME, POPUP_POS_CLASS, &placement);
  430.         bcopy( (char *) resourcePlacement, (char *) &placement,
  431.                     sizeof(popupPosResources) );
  432.         }
  433.  
  434.         }
  435.  
  436.     if ((tep = (textElementP) malloc(sizeof(textElement))) == NULL) {
  437.         showError("Too many windows are already open to show this file.");
  438.         return NULL;
  439.     }
  440.     tep->next = textElementHead;
  441.     textElementHead = tep;
  442.  
  443.     /* create TEXT display popup */
  444.         n=0;
  445.         XtSetArg(args[n], XtNtitle, "Gopher Text");  n++;
  446.         /*
  447.         XtSetArg(args[n], XtNiconName, "Gopher Text");  n++;
  448.         */
  449.     tep->textShell = XtCreatePopupShell("textShell",
  450.                     topLevelShellWidgetClass,
  451.                     topLevel, args, n);
  452.     
  453.     
  454.     /* create TEXT FORM */
  455.         n=0;
  456.     textForm = XtCreateManagedWidget("textForm", formWidgetClass,
  457.                     tep->textShell, args, n);
  458.  
  459.     /* create BUTTON BOX */
  460.         n=0;
  461.         XtSetArg(args[n], XtNorientation, XtorientHorizontal);  n++;
  462.         XtSetArg(args[n], XtNtop,    XawChainTop);  n++;
  463.         XtSetArg(args[n], XtNbottom,    XawChainTop);  n++;
  464.         XtSetArg(args[n], XtNleft,    XawChainLeft);  n++;
  465.         XtSetArg(args[n], XtNright,    XawChainLeft);  n++;
  466.     buttonBox = XtCreateManagedWidget("textButtonBox", boxWidgetClass,
  467.                     textForm, args, n);
  468.  
  469.     /* create TEXT display */
  470.         n=0;
  471.         XtSetArg(args[n], XtNstring, "");  n++;
  472.         XtSetArg(args[n], XtNeditType, XawtextRead);  n++;
  473.         XtSetArg(args[n], XtNscrollVertical,
  474.                     XawtextScrollWhenNeeded);  n++;
  475.         XtSetArg(args[n], XtNfromVert,    buttonBox);  n++;
  476.         XtSetArg(args[n], XtNtop,    XawChainTop);  n++;
  477.         XtSetArg(args[n], XtNbottom,    XawChainBottom);  n++;
  478.         XtSetArg(args[n], XtNleft,    XawChainLeft);  n++;
  479.         XtSetArg(args[n], XtNright,    XawChainRight);  n++;
  480.     tep->textDisplay = XtCreateManagedWidget("textDisplay",
  481.                     asciiTextWidgetClass,
  482.                     textForm, args, n);
  483.         setTextWidgetSize(tep->textDisplay, 80, 24);
  484.  
  485. #ifndef XGOPHER_X11R6
  486.         /* add the key word sink */
  487.         {
  488. #define            TAB_COUNT    32    /* same as in AsciiText.c */
  489.             Widget    kwSink;
  490.             int    i, tabs[TAB_COUNT], tab;
  491.  
  492.             kwSink = XtCreateWidget("kwSink",
  493.                     keyWSinkObjectClass,
  494.                     tep->textDisplay, args, n);
  495.  
  496.             for (i=0, tab=0 ; i < TAB_COUNT ; i++)
  497.                 tabs[i] = (tab += 8);
  498.             XawTextSinkSetTabs(kwSink, TAB_COUNT, tabs);
  499.  
  500.             n=0;
  501.             XtSetArg(args[n], XtNtextSink, kwSink);  n++;
  502.             XtSetValues(tep->textDisplay, args, n);
  503.         }
  504. #endif
  505.  
  506.  
  507.     /* create DONE button */
  508.     
  509.         n=0;
  510.     doneButton = XtCreateManagedWidget("textDone", commandWidgetClass,
  511.                     buttonBox, args, n);
  512.         XtAddCallback(doneButton, XtNcallback,
  513.                 doneProc, (XtPointer) tep);
  514.  
  515.     /* create PAGE_DOWN button */
  516.     
  517.         n=0;
  518. #ifndef XGOPHER_X11R4
  519.         XtSetArg(args[n], XtNleftBitmap, pageDownPixmap);  n++;
  520. #endif
  521.     pageDownButton = XtCreateManagedWidget("textPageDown",
  522.                     commandWidgetClass,
  523.                     buttonBox, args, n);
  524.         XtAddCallback(pageDownButton, XtNcallback,
  525.                 pageDownProc, (XtPointer) tep->textDisplay);
  526.  
  527.     /* create PAGE_UP button */
  528.     
  529.         n=0;
  530. #ifndef XGOPHER_X11R4
  531.         XtSetArg(args[n], XtNleftBitmap, pageUpPixmap);  n++;
  532. #endif
  533.     pageUpButton = XtCreateManagedWidget("textPageUp", commandWidgetClass,
  534.                     buttonBox, args, n);
  535.         XtAddCallback(pageUpButton, XtNcallback,
  536.                 pageUpProc, (XtPointer) tep->textDisplay);
  537.  
  538.     /* create PRINT button */
  539.     
  540.     if (appResources->allowPrint) {
  541.             n=0;
  542.         printButton = XtCreateManagedWidget("textPrint",
  543.                         commandWidgetClass,
  544.                         buttonBox, args, n);
  545.             XtAddCallback(printButton, XtNcallback,
  546.                     printProc, (XtPointer) tep);
  547.     }
  548.  
  549.     /* create SAVE button */
  550.     
  551.     if (appResources->allowSave) {
  552.             n=0;
  553.         saveButton = XtCreateManagedWidget("textSave",
  554.                         commandWidgetClass,
  555.                         buttonBox, args, n);
  556.             XtAddCallback(saveButton, XtNcallback,
  557.                     saveProc, (XtPointer) tep);
  558.     }
  559.  
  560.     /* create HOLD button */
  561.     
  562.     if (appResources->concurrentText > 0  &&  appResources->allowHold) {
  563.             n=0;
  564.         holdButton = XtCreateManagedWidget("textHold",
  565.                         commandWidgetClass,
  566.                         buttonBox, args, n);
  567.             XtAddCallback(holdButton, XtNcallback,
  568.                     holdProc, (XtPointer) tep);
  569.     }
  570.  
  571.     setPopupGeometry(tep->textShell, &placement);
  572.  
  573.         /* for ICCCM window manager protocol complience */
  574.  
  575.         XtOverrideTranslations (tep->textShell,
  576.             XtParseTranslationTable ("<Message>WM_PROTOCOLS: removeText()"));
  577.         XtRealizeWidget(tep->textShell);
  578.         (void) XSetWMProtocols (XtDisplay(tep->textShell),
  579.                 XtWindow(tep->textShell),
  580.                                 &wmDeleteAtom, 1);
  581.  
  582.     return tep;
  583. }
  584.  
  585.  
  586. /* saveItemInfo
  587.    copy info from the original gopher item, if any, to internal fields. */
  588.  
  589. saveItemInfo(localItem, gi, title)
  590. subItem        *localItem;
  591. gopherItemP    gi;
  592. char        *title;
  593. {
  594.     if (gi != (gopherItemP) NULL) {
  595.         strcpy (localItem->host, gi->host);
  596.         strcpy (localItem->title, USER_STRING(gi));
  597.     } else {
  598.         (localItem->host)[0] = NULLC;
  599.         strcpy (localItem->title, title);
  600.     }
  601. }
  602.  
  603.  
  604. /* getTextElement
  605.    find a free textElement structure or get a new one. */
  606.  
  607. static textElementP
  608. getTextElement(topLevel, class)
  609. Widget        topLevel;
  610. TextClass    class;
  611. {
  612.     textElementP    tep = NULL, p, oldest;
  613.     int        n;
  614.  
  615.     if (appResources->commonText) class = defaultTextClass;
  616.  
  617.     /* if concurrentText is set > 0, then we have to find
  618.        out how many of these displays are popped up and reuse the
  619.        oldest if necessary.  */
  620.  
  621.     if (appResources->concurrentText> 0) { 
  622.  
  623.         n=0;
  624.         oldest = textElementHead;
  625.         for (p=textElementHead; p!=NULL; p = p->next) {
  626.             if (!p->used) continue;
  627.             if (p->hold) continue;
  628.             if (p->class == class) {
  629.                 n++;
  630.                 if (p->seqNumber < oldest->seqNumber) {
  631.                     oldest = p;
  632.                 }
  633.             }
  634.         }
  635.         if (n >= appResources->concurrentText) {
  636.             tep = oldest;
  637.             freeTextResources(tep);
  638.  
  639.             return tep;
  640.         }
  641.     }
  642.  
  643.  
  644.     for (tep=textElementHead; (tep!=NULL && tep->used); tep = tep->next);
  645.  
  646.     if (tep == NULL) {
  647.         if ((tep = createTextShell(topLevel)) == NULL) {
  648.             return NULL;
  649.         }
  650.     }
  651.  
  652.     tep->seqNumber = textSeqNumber++;
  653.     tep->class     = class;
  654.     tep->hold      = False;
  655.     return tep;
  656. }
  657.  
  658.  
  659. /* displayTempFile
  660.    Load a text popup with a temp file */
  661.  
  662. void
  663. displayTempFile(topLevel, class, gi, title, fileName)
  664. Widget        topLevel;
  665. TextClass    class;
  666. gopherItemP    gi;
  667. char        *title;
  668. char        *fileName;
  669. {
  670.     Arg        args[10];
  671.     Cardinal    n;
  672.     char        *textFileName;
  673.     textElementP    tep;
  674.     Widget        kwSink;
  675.  
  676.  
  677.     tep = getTextElement(topLevel, class);
  678.  
  679.     if ((textFileName = (char *) XtMalloc(strlen(fileName)+1)) ==
  680.                                 NULL) {
  681.         showError("Unable to allocate additional memory.");
  682.         return;
  683.     }
  684.     strcpy(textFileName, fileName);
  685.     tep->displayedFile = textFileName;
  686.     tep->deleteFile    = True;
  687.     tep->used = True;
  688.     tep->wordList = NULL;
  689.     tep->stringValue = NULL;
  690.     saveItemInfo(&(tep->origFields), gi, title);
  691.  
  692. #ifndef XGOPHER_X11R6
  693.     /* set keyword resource in text sink */
  694.  
  695.     n = 0;
  696.     XtSetArg(args[n], XtNtextSink, &kwSink);  n++;
  697.     XtGetValues(tep->textDisplay, args, n);
  698.  
  699.     n = 0;
  700.     XtSetArg(args[n], XtNwordList, NULL);  n++;
  701.     XtSetValues(kwSink, args, n);
  702. #endif
  703.  
  704.     /* set title and file name */
  705.  
  706.     n = 0;
  707.     XtSetArg(args[n], XtNtitle, tep->origFields.title);  n++;
  708.     if (appResources->nameText) {
  709.         XtSetArg(args[n], XtNiconName, title);  n++;
  710.     }
  711.     XtSetValues(tep->textShell, args, n);
  712.  
  713.     n = 0;
  714.     XtSetArg(args[n], XtNtype, XawAsciiFile);  n++;
  715.     XtSetArg(args[n], XtNstring, textFileName);  n++;
  716.     XtSetValues(tep->textDisplay, args, n);
  717.  
  718.     positionAPopup(tep->textShell, topLevel, &placement);
  719.     XtPopup(tep->textShell, XtGrabNone);
  720.     return;
  721. }
  722.  
  723.  
  724. /* displayIndexTempFile
  725.    Load a text popup with a temp file and index words for highlighting */
  726.  
  727. void
  728. displayIndexTempFile(topLevel, class, gi, title, fileName, indexString)
  729. Widget        topLevel;
  730. TextClass    class;
  731. gopherItemP    gi;
  732. char        *title;
  733. char        *fileName;
  734. char        *indexString;
  735. {
  736.     Arg        args[10];
  737.     Cardinal    n;
  738.     char        *textFileName;
  739.     textElementP    tep;
  740.     Widget        kwSink;
  741.  
  742.  
  743.     tep = getTextElement(topLevel, class);
  744.  
  745.     if ((textFileName = (char *) XtMalloc(strlen(fileName)+1)) ==
  746.                                 NULL) {
  747.         showError("Unable to allocate additional memory.");
  748.         return;
  749.     }
  750.     strcpy(textFileName, fileName);
  751.     tep->displayedFile = textFileName;
  752.     tep->deleteFile    = True;
  753.     tep->used = True;
  754.     tep->stringValue = NULL;
  755.     saveItemInfo(&(tep->origFields), gi, title);
  756.  
  757.  
  758. #ifndef XGOPHER_X11R6
  759.     /* set keyword resource in text sink */
  760.  
  761.     n = 0;
  762.     XtSetArg(args[n], XtNtextSink, &kwSink);  n++;
  763.     XtGetValues(tep->textDisplay, args, n);
  764.  
  765.     n = 0;
  766.     if (indexString == NULL) {
  767.         tep->wordList = NULL;
  768.         XtSetArg(args[n], XtNwordList, NULL);  n++;
  769.     } else {
  770.         tep->wordList = makeWordList(indexString);
  771.         XtSetArg(args[n], XtNwordList, tep->wordList);  n++;
  772.     }
  773.     XtSetValues(kwSink, args, n);
  774. #endif
  775.  
  776.     /* set title and file name */
  777.  
  778.     n = 0;
  779.     XtSetArg(args[n], XtNtitle, tep->origFields.title);  n++;
  780.     if (appResources->nameText) {
  781.         XtSetArg(args[n], XtNiconName, title);  n++;
  782.     }
  783.     XtSetValues(tep->textShell, args, n);
  784.  
  785.     n = 0;
  786.     XtSetArg(args[n], XtNtype, XawAsciiFile);  n++;
  787.     XtSetArg(args[n], XtNstring, textFileName);  n++;
  788.     XtSetValues(tep->textDisplay, args, n);
  789.  
  790.     positionAPopup(tep->textShell, topLevel, &placement);
  791.     XtPopup(tep->textShell, XtGrabNone);
  792.     return;
  793. }
  794.  
  795.  
  796. /* displayTextString
  797.    Load a text popup with the contents of a text string */
  798.  
  799. void
  800. displayTextString(topLevel, class, gi, title, string)
  801. Widget        topLevel;
  802. TextClass    class;
  803. gopherItemP    gi;
  804. char        *title;
  805. char        *string;
  806. {
  807.     Arg        args[10];
  808.     Cardinal    n;
  809.     textElementP    tep;
  810.     Widget        kwSink;
  811.  
  812.  
  813.     tep = getTextElement(topLevel, class);
  814.  
  815.     tep->displayedFile = NULL;
  816.     tep->deleteFile    = False;
  817.     tep->used       = True;
  818.     tep->wordList       = NULL;
  819.     tep->stringValue   = string;
  820.     saveItemInfo(&(tep->origFields), gi, title);
  821.  
  822. #ifndef XGOPHER_X11R6
  823.     /* set keyword resource in text sink */
  824.  
  825.     n = 0;
  826.     XtSetArg(args[n], XtNtextSink, &kwSink);  n++;
  827.     XtGetValues(tep->textDisplay, args, n);
  828.  
  829.     n = 0;
  830.     XtSetArg(args[n], XtNwordList, NULL);  n++;
  831.     XtSetValues(kwSink, args, n);
  832. #endif
  833.  
  834.     /* set title and file name */
  835.  
  836.     n = 0;
  837.     XtSetArg(args[n], XtNtitle, tep->origFields.title);  n++;
  838.     if (appResources->nameText) {
  839.         XtSetArg(args[n], XtNiconName, title);  n++;
  840.     }
  841.     XtSetValues(tep->textShell, args, n);
  842.  
  843.     n = 0;
  844.     XtSetArg(args[n], XtNtype, XawAsciiString);  n++;
  845.     XtSetArg(args[n], XtNstring, string);  n++;
  846.     XtSetValues(tep->textDisplay, args, n);
  847.  
  848.     positionAPopup(tep->textShell, topLevel, &placement);
  849.     XtPopup(tep->textShell, XtGrabNone);
  850.     return;
  851. }
  852.